package Modele;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.Integer;
import java.lang.String;
import java.util.ArrayList;

//import com.sun.tools.javac.util.Pair;
/**
 * Classe permettant la gestion du modèle
 * @author philippestepniewski
 */
public class gestModele implements IModel{

	public gestModele(){

	}
        /**
         * Execute l experience fichierExp
         * @param fichierExp -- Nom de l experience -- String
         */
	public void executerExp(File fichierExp) {
		LuaJava.runScript(fichierExp);
	}
        
        /**
         * Retourne la classification des exemples
         * @return
         */
	public ArrayList<Pair<Integer,Integer>> getResultat(String name){
		try
		{
			Thread.sleep(2000);
		} catch (InterruptedException e) {

			System.out.println("Trop presse, peu pas attendre !");
		}
		ArrayList<Pair<Integer,Integer>> res = Reader.readClassif(name);
		if(res.isEmpty()){
			return null;
		}
		else{
			return(Reader.readClassif(name));
		}

	}






        /**
         * Récupère l'erreur quadratique au cours des itérations
         * @param name
         * @return l'erreur quadratique au cours des itérations
         */
	public ArrayList<Double> getErreur(String name){
		ArrayList<Double> res=Reader.readErreur(name);
		File[] files = null;
		File directoryToScan = new File(".");
		files = directoryToScan.listFiles();
		for(int i = 0; i < files.length; i++)
		{
			if(files[i].getName().contains("Erreur"))
			{
				files[i].delete();
			}
		}
		return res;
	}

        /**
         * Calcul le pourcentage de neurones de chaque couche dans chaque cluster de Kmeans
         * @param arraykmeans tableau contenant l'apparatenance de chaque neurones au clusters de kmeans
         * @param sizeCouches tableau contenant le nombre de neurones dans chaque couche
         * @param kdekmeans k de kmeans
         * @return le pourcentage de neurones de chaque couche dans chaque cluster de Kmeans
         */
        public ArrayList<double[]> pourcentageNeuKmeans(ArrayList<ArrayList<Integer>> arraykmeans,int[] sizeCouches,int kdekmeans){
                ArrayList<double[]> histo= new ArrayList<double[]>();
                double temp[]=new double[kdekmeans];
                double sum;
                        int nbocc;
                for(int i=0;i<sizeCouches.length;i++){
                        temp=new double[kdekmeans];
                    for(int l=1;l<=kdekmeans;l++){
                        nbocc=0;
                        for(int j=0;j<arraykmeans.get(i).size();j++){
                            if(arraykmeans.get(i).get(j)==l){
                                nbocc++;
                            }
                        }
                        nbocc=(nbocc*100)/sizeCouches[i];
                        temp[l-1]=nbocc;
                    }
                    histo.add(temp);
                }
                return histo;
        }





        
        /**
         * Génère des données pour le curriculum avec les paramètres adéquates
         * @param name nom du jeu de données
         * @param level niveu de difficulté
         * @param size format des donneés
         * @param nb nombre de données
         * @return
         */
	public boolean genereDataSet(String name,int level, int size, int nb)
	{
		try {
			WriterDataSet.writeForm(name,level,size,nb);
			return true;
		} catch (IOException e) {
			return false;
		}

	}
        
         /**
         * Genere une exp qui ne renvoie que l'activation avant et apres apprentissage
         * @param NomFic -- Nom de l experience -- String
         * @param nbIn -- Input -- Int
         * @param nbOut -- Output -- Int
         * @param listeCouche -- Nombres de couches et de neurones par couche -- ArrayList<Integer>
         * @param fichiersData -- Listes des fichiers contenant les exemples -- ArrayList<String>
         * @param sparse -- Si les exemples sont dans des fichiers Sparse -- boolean
         * @param epsilon -- LearningRate -- double
         * @param autoEncode -- Avec ou Sans pre-entrainement -- boolean
         * @param save -- Permet de sauvegarder le pmc, celui-ci aura le nom de l exp -- boolean
         * @return true si l experience est generee
         */
	public boolean genererExperienceTrain(String NomFic, int nbIn, int nbOut,
			ArrayList<Integer> listeCouche, ArrayList<String> fichiersData,
			boolean sparse, double epsilon, boolean autoEncode, boolean save) {
		File fichierExp = new File(NomFic);
		System.out.println(fichierExp.getAbsolutePath());
		try {
			Writer.writeHead(fichierExp, nbIn, nbOut, listeCouche);
			Writer.writeDataSet(fichierExp,sparse,fichiersData,nbIn,nbOut);

			if(autoEncode)
				Writer.writeEncoder(fichierExp);

			Writer.writeTrain2(fichierExp,epsilon);

			if(save)
				Writer.writeSave(fichierExp,listeCouche);

			Writer.writeActivMatriceKmeans(fichierExp,listeCouche,5,100);
			return true;

		} catch (IOException e) {
			e.printStackTrace();
		}
		return false;
	}

        /**
         * Génère une expérience avec chargement de PMC
         * @param NomFic nom du fichier expérience
         * @param nbIn nombre d'entrée du PMC
         * @param nbOut nombre de sortie du PMC
         * @param pmc chemin du pmc sauvegarde
         * @param sparse format des données
         * @param fichiersData chemins des fichiers de données
         * @param epsilon
         * @return
         */
	public boolean genererPMC(String NomFic, int nbIn, int nbOut, String pmc, boolean sparse,ArrayList<String> fichiersData, double epsilon)
	{
		File fichierExp = new File(NomFic);
                ArrayList<Integer> listeCouche=new ArrayList<Integer>() ;
                String tabval[]=pmc.split("_");
                for(int i=1;i<tabval.length;i++){
                    listeCouche.add(Integer.parseInt(tabval[i]));
                }

		System.out.println("Here");
		try {
			Writer.writeHeadPMC(fichierExp, pmc);
			//Writer.writeActiLua(fichierExp,sparse,fichiersData,nbIn,nbOut);
			Writer.writeDataSet(fichierExp, sparse, fichiersData, nbIn, nbOut);
			Writer.writeTrain2(fichierExp, epsilon);
			Writer.writeSave(fichierExp,listeCouche);
                        Writer.writeActivMatriceKmeans(fichierExp,listeCouche,5,100);
			return true;
		} catch (IOException e) {
			e.printStackTrace();
		}

		return false;
	}

	/**
         * Genere une exp qui renvoie l activation avant, pendant et apres apprentissage
         * @param NomFic -- Nom de l experience -- String
         * @param nbIn -- Input -- Int
         * @param nbOut -- Output -- Int
         * @param listeCouche -- Nombres de couches et de neurones par couche -- ArrayList<Integer>
         * @param fichiersData -- Listes des fichiers contenant les exemples -- ArrayList<String>
         * @param sparse -- Si les exemples sont dans des fichiers Sparse -- boolean
         * @param epsilon -- LearningRate -- double
         * @param autoEncode -- Avec ou Sans pre-entrainement -- boolean
         * @param save -- Permet de sauvegarder le pmc, celui-ci aura le nom de l exp -- boolean
         * @return true si l experience est generee
         */
	public boolean genererExperienceFor(String NomFic, int nbIn,
			int nbOut, ArrayList<Integer> listeCouche,
			ArrayList<String> fichiersData, boolean sparse, double epsilon,
			boolean autoEncode, boolean save) {
		File fichierExp = new File(NomFic);
		System.out.println(fichierExp.getAbsolutePath());
		try {
			Writer.writeHead(fichierExp, nbIn, nbOut, listeCouche);
			Writer.writeDataSet(fichierExp,sparse,fichiersData,nbIn,nbOut);

			if(autoEncode)
				Writer.writeEncoder(fichierExp);

			Writer.writeTrain(fichierExp,epsilon);

			if(save)
				Writer.writeSave(fichierExp,listeCouche);

			Writer.writeActivMatriceKmeans(fichierExp,listeCouche,5,100);
			return true;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return false;
	}

        /**
         * Retourne les activations de l experience expName
         * @param expName -- Le nom de l experience
         */
	public ArrayList<ArrayList<ArrayList<double[]>>> getAllActiv(
			String expName)
			{
		ArrayList<ArrayList<ArrayList<double[]>>> res=new ArrayList<ArrayList<ArrayList<double[]>>>();
		for(int i = 0; i < 50; i++)
		{
			ArrayList<ArrayList<double[]>> temp = new ArrayList<ArrayList<double[]>>();
			res.add(temp);
		}

		File[] files = null;
		File directoryToScan = new File(".");
		files = directoryToScan.listFiles();
		boolean bool = true;
		while(bool)
		{
			try
			{
				Thread.sleep(1000);
			} catch (InterruptedException e) {

				System.out.println("Trop presse, peu pas attendre !");
			}
			files = directoryToScan.listFiles();
			bool = existFichier(files,"temp.lock");
			for(int i = 0; i < files.length; i++)
			{
				if(files[i].getName().charAt(0) == 'a' && files[i].getName().contains(expName))
				{
					String name = files[i].getName();
					String[] nom = name.split("_");
					int ptr = Integer.parseInt(nom[nom.length - 1]);
					ArrayList<double[]> act = Reader.read_activation(name);
					res.get(ptr-1).add(act);
					files[i].delete();
				}
			}
		}
		return res;
			}
        /**
         * Vérifie l'existence d'un fichier dans une liste de fichiers
         * @param files la liste de fichiers
         * @param what le nom du fichier a trouver
         * @return vrai ou faux 
         */
	private boolean existFichier(File[] files,String what)
	{
		for(int i = 0; i < files.length; i++){
			if(files[i].getName().equalsIgnoreCase(what))
			{
				//System.out.println("There no need for proof");
				return true;
			}
		}
		return false;
	}

        /**
         *  récupère les représentant de chaque cluster de kmeans, pour toutes les couches
         * @param nbCouches
         * @return la liste des représentant des clusters, par couche
         */
	public ArrayList<ArrayList<double[]>> getKmeans(int nbCouches){
		ArrayList<ArrayList<double[]>> toutKmeans=new ArrayList<ArrayList<double[]>>();
		File[] files = null;
		File directoryToScan = new File(".");
		files = directoryToScan.listFiles();
		boolean bool = true;
		while(bool)
		{
			try
			{
				Thread.sleep(10);
			} catch (InterruptedException e) {

				System.out.println("Trop presse, peu pas attendre !");
			}

			files = directoryToScan.listFiles();
			bool = existFichier(files,"temp.lock");
                        for(int i=0;i<nbCouches;i++){
			toutKmeans.add(i,Reader.read_kmeans("KmeansVect"+i));
		}
		for(int i = 0; i < files.length; i++)
		{
			if(files[i].getName().contains("KmeansVect"))
			{
				files[i].delete();
			}
		}

		}


		

		return toutKmeans;
	}


        /**
         * Récupère la liste d'appartenance des neurones au clusters pour toutes les couches
         * @param nbcouches
         * @return la liste d'appartenance des neurones au clusters pour toutes les couches
         */
        public ArrayList<ArrayList<Integer>> readAllCluster(int nbcouches){
            File[] files = null;
		File directoryToScan = new File(".");
		files = directoryToScan.listFiles();
		boolean bool = true;
            ArrayList<ArrayList<Integer>> toutclust=new ArrayList<ArrayList<Integer>>();
		while(bool)
		{
			try
			{
				Thread.sleep(10);
			} catch (InterruptedException e) {

				System.out.println("Trop presse, peu pas attendre !");
			}

			files = directoryToScan.listFiles();
			bool = existFichier(files,"temp.lock");
                        for(int i=0;i<nbcouches;i++){
                            toutclust.add(i,Reader.readCluster(i));
                        }
		for(int i = 0; i < files.length; i++)
		{
			if(files[i].getName().contains("Ykmean"))
			{
				files[i].delete();
			}
		}

		}

            return toutclust;
        }


        /**
         * Génère une expérience avec curriculum
         * @param nomFic nom de l'experience
         * @param save sauvegarde ou pas du PMC
         * @param nbInputs nombre d'entrées des données
         * @param nbExemples nombre de données
         * @param nbIterations nombre d'itérations
         * @param curric comparatif avec curric ou sans;
         * @param learningRate pas de la descente de gradient
         * @return
         */
        public boolean genererExperienceCurric(String nomFic, boolean save, int nbApprentissage, int nbTest, int nbInputsInit, int nbInputsMax, int pasInput, int nbIterations,  double learningRate) {
                File fichierExp = new File(nomFic);
                System.out.println(fichierExp.getAbsolutePath());
                try {
                        WriterCurric.writeFichierCurric(fichierExp, nbApprentissage, nbTest, nbInputsInit, nbInputsMax, pasInput, nbIterations, learningRate);
                        if(save)
                                Writer.writeSave(fichierExp,null);

                        return true;

                } catch (IOException e) {
                        e.printStackTrace();
                }
                return false;
        }

    /**
     * Récupère le taux de réusite pour une expérience
     * @param nomExp le nom de l'expérience
     * @return le taux de réussite
     */
    public double getTaux(String nomExp) {
            double taux= Reader.readTaux(nomExp);
            return taux;
    }


         /**
         * Retourne le resultat du curriculum learning
         * @return
         */
	public ArrayList<Pair<Integer,Double>> getCurric(String name){
		try
		{
			Thread.sleep(25000);
		} catch (InterruptedException e) {

			System.out.println("Trop presse, peu pas attendre !");
		}

                                ArrayList<Pair<Integer,Double>> res = Reader.readCurric(name);


			return(Reader.readCurric(name));


	}
}